/*
 * load_cg.c
 *
 *  Created on: 2012/09/04
 *      Author: shenming
 */

#include <stdio.h>
#include "sqlite3.h"
#include "db_def.h"
#include "core.h"
#include "core_internal.h"
#include "Id.h"
#include "../../CCore/parser/coredef.h"
#include "../../CCore/table/table.h"
#include "../../CCore/parser/cc/cc.h"
#include "../../CCore/table/core_table.h"

/*TBL_MEMBER*/
static INT loadMember(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_MEMBER);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stMemberSymbolAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stMemberSymbolAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stMemberSymbolAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stMemberSymbolAccess.symClass.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_CLASS - 1));

		stMemberSymbolAccess.type.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_TYPE - 1));

		stMemberSymbolAccess.name.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, MEMBER_NAME - 1));

		stMemberSymbolAccess.value.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_VALUE - 1));

		stMemberSymbolAccess.codeScp.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_CODESCOPE - 1));

		stMemberSymbolAccess.next.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_NEXT - 1));

		stMemberSymbolAccess.memOffset.set(tblIndex,
				sqlite3_column_int(stmt, MEMBER_MEMOFS - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CONSTANT*/
typedef struct _CONSTANTINFO {
	BOOL bFloating;
	U2 size;
	union {
		struct {
			SCHAR bSigned;
			SCHAR sign;
			U8 u8Remainder; /* Absolute value */
		} integer;
		struct {
			LDOUBLE dbValue;
		} floating;
	} value;
	RBTREE rbtree;
} CONSTANTINFO, *PCONSTANTINFO;
extern AST addOuterValue(CONSTANTINFO);
static INT loadConstant(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	CONSTANTINFO info;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_CONSTANT);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stConstantAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {

		info.bFloating = sqlite3_column_int(stmt, CONSTANT_B_FLOATING - 1);
		info.size = sqlite3_column_int(stmt, CONSTANT_SIZE - 1);
		if (info.bFloating) {
			info.value.floating.dbValue = sqlite3_column_double(stmt,
			CONSTANT_DOUBLEVALUE - 1);
		} else {
			info.value.integer.bSigned = sqlite3_column_int(stmt,
			CONSTANT_B_SIGNED - 1);
			if (sqlite3_column_int(stmt, CONSTANT_B_NEG - 1)) {
				info.value.integer.sign = -1;
			} else {
				info.value.integer.sign = 1;
			}
			info.value.integer.u8Remainder = sqlite3_column_int64(stmt,
			CONSTANT_INTVALUE - 1);
		}
		addOuterValue(info);
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_GBLLINKAGE*/
static INT loadGblLinkage(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_GBLLINKAGE);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stGblLinkageAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stGblLinkageAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stGblLinkageAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stGblLinkageAccess.vari.set(tblIndex,
				sqlite3_column_int(stmt, GBLLINK_SYMDEFINFO - 1));

		stGblLinkageAccess.refer.set(tblIndex,
				sqlite3_column_int(stmt, GBLLINK_B_REF - 1));

		stGblLinkageAccess.bExternal.set(tblIndex,
				sqlite3_column_int(stmt, GBLLINK_B_EXTERNAL - 1));

		stGblLinkageAccess.bFunction.set(tblIndex,
				sqlite3_column_int(stmt, GBLLINK_B_FUNCTION - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_FUNCTIONIDINFO*/
static INT loadFunctionIdInfo(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_FUNCTIONIDINFO);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stFunctionInfoAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stFunctionInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stFunctionInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stFunctionInfoAccess.symClass.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_SYM_CLASS - 1));

		stFunctionInfoAccess.linkage.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_LINKAGE_INFO - 1));

		stFunctionInfoAccess.type.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_TYPE_INFO - 1));

		stFunctionInfoAccess.name.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, FUNC_SYMBOL_NAME - 1));

		stFunctionInfoAccess.functionEntry.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_ENTRY - 1));

		stFunctionInfoAccess.functionExit.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_EXIT - 1));

		stFunctionInfoAccess.codeScp.set(tblIndex,
				sqlite3_column_int(stmt, FUNC_CODE_SCOPE_INFO - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_VARIABLEINFO*/
static INT loadVariableInfo(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_VARIABLEINFO);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stVariableInfoAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stVariableInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stVariableInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stVariableInfoAccess.symClass.set(tblIndex,
				sqlite3_column_int(stmt, VAR_SYM_CLASS - 1));

		stVariableInfoAccess.linkage.set(tblIndex,
				sqlite3_column_int(stmt, VAR_LINKAGE_INFO - 1));

		stVariableInfoAccess.type.set(tblIndex,
				sqlite3_column_int(stmt, VAR_TYPE_INFO - 1));

		stVariableInfoAccess.name.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, VAR_SYMBOL_NAME - 1));

		stVariableInfoAccess.codeScp.set(tblIndex,
				sqlite3_column_int(stmt, VAR_CODE_SCOPE_INFO - 1));

		stVariableInfoAccess.dataSection.set(tblIndex,
				sqlite3_column_int(stmt, VAR_DATA_SECTION_INFO - 1));

		stVariableInfoAccess.initialCmdBegin.set(tblIndex,
				sqlite3_column_int(stmt, VAR_INITIAL_CMDBEGIN - 1));

		stVariableInfoAccess.initialCmdEnd.set(tblIndex,
				sqlite3_column_int(stmt, VAR_INITIAL_CMDEND - 1));

		stVariableInfoAccess.value.set(tblIndex,
				sqlite3_column_int64(stmt, VAR_VALUE_INFO - 1));

		stVariableInfoAccess.offset.set(tblIndex,
				sqlite3_column_int64(stmt, VAR_OFFSET - 1));

		stVariableInfoAccess.length.set(tblIndex,
				sqlite3_column_int(stmt, VAR_LENGTH - 1));

		stVariableInfoAccess.bSizeVariable.set(tblIndex,
				sqlite3_column_int(stmt, VAR_B_SIZEVARI - 1));

		stVariableInfoAccess.child.set(tblIndex,
				sqlite3_column_int(stmt, VAR_CHILD - 1));

		stVariableInfoAccess.parent.set(tblIndex,
				sqlite3_column_int(stmt, VAR_PARENT - 1));

		stVariableInfoAccess.next.set(tblIndex,
				sqlite3_column_int(stmt, VAR_NEXT - 1));

		stVariableInfoAccess.prev.set(tblIndex,
				sqlite3_column_int(stmt, VAR_PREV - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_COMMANDLIST*/
static INT loadCmdList(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_COMMANDLIST);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stCmdListAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCmdListAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stCmdListAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stCmdListAccess.opKind.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_KIND - 1));

		//TODO
//		stCmdListAccess.set(tblIndex,sqlite3_column_int(stmt, CMDLIST_B_INLOOP - 1));

		stCmdListAccess.codeScp.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_CODESCOPE - 1));

		stCmdListAccess.type.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_TYPE - 1));

		stCmdListAccess.function.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_FUNC - 1));

		stCmdListAccess.leftOperand.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_LEFT - 1));

		stCmdListAccess.rightOperand.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_RIGHT - 1));

		stCmdListAccess.before.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_PREV - 1));

		stCmdListAccess.next.set(tblIndex,
				sqlite3_column_int(stmt, CMDLIST_NEXT - 1));

		stCmdListAccess.label.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, CMDLIST_NAME - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_OPERAND*/
static INT loadOperand(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_OPERAND);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stOperandAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stOperandAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stOperandAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stOperandAccess.kind.set(tblIndex,
				sqlite3_column_int(stmt, OPERAND_KIND - 1));

		stOperandAccess.parameter.set(tblIndex,
				sqlite3_column_int(stmt, OPERAND_PARAM - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_LINKTYPEINFO*/
static INT loadLinkType(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_LINKTYPEINFO);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stLinkTypeInfoAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stLinkTypeInfoAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stLinkTypeInfoAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stLinkTypeInfoAccess.typeKind.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_KIND - 1));

		stLinkTypeInfoAccess.signFlag.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_SIGNED - 1));

		stLinkTypeInfoAccess.longShortFlg.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_LONGSHORT - 1));

		stLinkTypeInfoAccess.intFloat.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_INTFLOAT - 1));

		stLinkTypeInfoAccess.typeQual.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_TYPEQUAL - 1));

		stLinkTypeInfoAccess.bSizeUnDefined.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_B_UNDEFINED - 1));

		stLinkTypeInfoAccess.bVariableSize.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_B_VARSIZE - 1));

		stLinkTypeInfoAccess.size.set(tblIndex,
				sqlite3_column_int64(stmt, LINKTYPE_SIZE - 1));

		stLinkTypeInfoAccess.elementType.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_ORIGIN - 1));

		stLinkTypeInfoAccess.noQualType.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_NOQUAL - 1));

		stLinkTypeInfoAccess.memChain.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_MEMCHAIN - 1));

		stLinkTypeInfoAccess.tagName.set(tblIndex,
				(PSZ) sqlite3_column_text(stmt, LINKTYPE_NAME - 1));

		stLinkTypeInfoAccess.next.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_NEXT - 1));

		stLinkTypeInfoAccess.cnter.set(tblIndex,
				sqlite3_column_int(stmt, LINKTYPE_CNT - 1));
	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_TRANSUNIT*/
static INT loadTransUnit(sqlite3 * db) {
	INT rc = 0;
	PSZ sql_get = NULL;
	const char *zTail;
	sqlite3_stmt * stmt = NULL;

	AST tblIndex = 0;

	sql_get = sqlite3_mprintf("SELECT * FROM %q ORDER BY TblIndex;",
			TBL_TRANSUNIT);
	rc = sqlite3_prepare(db, (const char *) sql_get, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_get != NULL ) {
			sqlite3_free(sql_get);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	stCoreTranslationUnitAccess.clear();

	while (sqlite3_step(stmt) == SQLITE_ROW) {
		stCoreTranslationUnitAccess.alloc(1);
		tblIndex = sqlite3_column_int(stmt, P_TABLE_INDEX - 1);

		if (tblIndex != stCoreTranslationUnitAccess.getMax()) {
			rc = COEXIT_ERROR;
			break;
		}

		stCoreTranslationUnitAccess.fileindex.set(tblIndex,
				sqlite3_column_int(stmt, TU_FILEINDEX - 1));

		stCoreTranslationUnitAccess.declarationchain.set(tblIndex,
				sqlite3_column_int(stmt, TU_DEC_CHAIN - 1));

		stCoreTranslationUnitAccess.preVariMax.set(tblIndex,
				sqlite3_column_int(stmt, TU_VARI_MAX - 1));

		stCoreTranslationUnitAccess.preFuncMax.set(tblIndex,
				sqlite3_column_int(stmt, TU_FUNC_MAX - 1));

		stCoreTranslationUnitAccess.preLinkageMax.set(tblIndex,
				sqlite3_column_int(stmt, TU_LINK_MAX - 1));

	}
	if (sql_get != NULL ) {
		sqlite3_free(sql_get);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*load transunit*/
INT DLL_EXPORT loadCgTu(sqlite3 * db) {
	INT rc = 0;
	rc = loadTransUnit(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}
	return COEXIT_SUCCESS;
}

/*load cg*/
INT DLL_EXPORT loadCgData(sqlite3 * db) {
	INT rc = 0;

	rc = loadTransUnit(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadMember(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadConstant(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadGblLinkage(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadFunctionIdInfo(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadVariableInfo(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadCmdList(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadOperand(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = loadLinkType(db);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	return COEXIT_SUCCESS;
}

